/*!
\copyright  Copyright (c) 2022 Qualcomm Technologies International, Ltd.
            All Rights Reserved.
            Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\file
\brief
*/

#include "tmap_server_role_advertising.h"
#include "le_advertising_manager.h"
#include "gatt_tmas_server_uuids.h"
#include "gatt_tmas_server.h"

#include <logging.h>
#include <panic.h>
#include <stdlib.h>

#define TMAP_SERVER_SIZE_ADVERT                  6

/*! Service Data (16-bit default). */
#define TMAP_BLE_AD_TYPE_SERVICE_DATA            0x16


#if defined(INCLUDE_LE_AUDIO_BROADCAST)
#define TMAP_BROADCAST_ROLE TMAP_ROLE_BROADCAST_MEDIA_RECEIVER
#else
#define TMAP_BROADCAST_ROLE 0
#endif

#if defined(INCLUDE_LE_AUDIO_UNICAST)

#ifndef DISABLE_LE_AUDIO_VOICE
#define TMAP_ROLE_CALL_TERMINAL_SUPPORT             TMAP_ROLE_CALL_TERMINAL
#else
#define TMAP_ROLE_CALL_TERMINAL_SUPPORT             0
#endif

#ifndef DISABLE_LE_AUDIO_MEDIA
#define TMAP_ROLE_UNICAST_MEDIA_RECEIVER_SUPPORT    TMAP_ROLE_UNICAST_MEDIA_RECEIVER
#else
#define TMAP_ROLE_UNICAST_MEDIA_RECEIVER_SUPPORT    0
#endif

#define TMAP_UNICAST_ROLE   (TMAP_ROLE_CALL_TERMINAL_SUPPORT | TMAP_ROLE_UNICAST_MEDIA_RECEIVER_SUPPORT)

#else /* !INCLUDE_LE_AUDIO_UNICAST */

#define TMAP_UNICAST_ROLE   0

#endif /* INCLUDE_LE_AUDIO_UNICAST */

/*! Tmap supporting role characteristic valus (UMR, BMR, CT))*/
#define TMAP_ROLE_VALUE     (TMAP_BROADCAST_ROLE | TMAP_UNICAST_ROLE)

#define TMAP_DEBUG_INFO     DEBUG_LOG

static le_adv_item_data_t tmap_server_advert;
static le_adv_item_handle tmap_server_registered_handle = NULL;

static const uint8 tmapServerAdvertData[TMAP_SERVER_SIZE_ADVERT] = {
    TMAP_SERVER_SIZE_ADVERT - 1,
    TMAP_BLE_AD_TYPE_SERVICE_DATA,
    /* TMAS UUID */
    UUID_TELEPHONY_MEDIA_AUDIO_SERVICE & 0xFF,
    UUID_TELEPHONY_MEDIA_AUDIO_SERVICE >> 8,
    /* TMAP ROLE*/
    (TMAP_ROLE_VALUE) & 0xFF,
    (TMAP_ROLE_VALUE) >> 8,
};

static bool tmapServer_GetItemData(le_adv_item_data_t * item)
{
    if (tmap_server_advert.data == NULL)
    {
        uint8 * data = NULL;

        data = PanicUnlessMalloc(TMAP_SERVER_SIZE_ADVERT);
        memcpy(data, tmapServerAdvertData, TMAP_SERVER_SIZE_ADVERT);

        tmap_server_advert.data = data;
        tmap_server_advert.size = TMAP_SERVER_SIZE_ADVERT;

        TMAP_DEBUG_INFO("tmapServer_GetItemData size:%d", tmap_server_advert.size);
    }
    *item = tmap_server_advert;
    return TRUE;
}

static void tmapServer_ReleaseItemData(void)
{
    if(tmap_server_advert.data != NULL)
    {
        free((void *)tmap_server_advert.data);
        tmap_server_advert.data = NULL;
    }
}

#ifndef INCLUDE_LEGACY_LE_ADVERTISING_MANAGER

static bool tmapServer_GetItemInfo(le_adv_item_info_t * info)
{
    PanicNull(info);
    *info = (le_adv_item_info_t){ .placement = le_adv_item_data_placement_advert,
                                    .type = le_adv_type_extended_connectable,
                                    .data_size = TMAP_SERVER_SIZE_ADVERT };
    return TRUE;
}

le_adv_item_callback_t tmapServer_AdvertisingManagerCallback =
{
    .GetItemData = &tmapServer_GetItemData,
    .ReleaseItemData = &tmapServer_ReleaseItemData,
    .GetItemInfo = &tmapServer_GetItemInfo
};

#else

#define TMAP_SERVER_NUMBER_ADVERT_DATA_ITEMS     1

static bool tmapServer_CanAdvertise(const le_adv_data_params_t * params)
{
    bool can_advertise = FALSE;
    if (params->data_set == le_adv_data_set_extended_handset
            && params->completeness == le_adv_data_completeness_full
            && params->placement == le_adv_data_placement_advert)
    {
        can_advertise = TRUE;
    }

    return can_advertise;
}

static unsigned int tmapServer_GetNumberOfAdvertisingItems(const le_adv_data_params_t * params)
{
    if (tmapServer_CanAdvertise(params))
    {
        return TMAP_SERVER_NUMBER_ADVERT_DATA_ITEMS;
    }

    return 0;
}

static le_adv_data_item_t tmapServer_GetAdvertisingData(const le_adv_data_params_t * params, unsigned int index)
{
    /* Only one adv data item supported. If more items are needed, this function must be updated */
    PanicFalse(index == 0);
    le_adv_data_item_t item = { .size = 0, .data = NULL };
    if (tmapServer_CanAdvertise(params))
    {
        tmapServer_GetItemData(&item);
        return item;
    }

    Panic();
    return item;
}

static void tmapServer_ReleaseAdvertisingData(const le_adv_data_params_t * params)
{
    UNUSED(params);
    tmapServer_ReleaseItemData();
}

le_adv_data_callback_t tmapServer_AdvertisingManagerCallback =
{
    .GetNumberOfItems = &tmapServer_GetNumberOfAdvertisingItems,
    .GetItem = &tmapServer_GetAdvertisingData,
    .ReleaseItems = &tmapServer_ReleaseAdvertisingData
};

#endif

bool TmapServer_SetupLeAdvertisingData(void)
{
#ifndef INCLUDE_LEGACY_LE_ADVERTISING_MANAGER
    tmap_server_registered_handle = LeAdvertisingManager_RegisterAdvertisingItemCallback(NULL, &tmapServer_AdvertisingManagerCallback);
#else
    tmap_server_registered_handle = LeAdvertisingManager_Register(NULL, &tmapServer_AdvertisingManagerCallback);
#endif
    return (tmap_server_registered_handle ? TRUE : FALSE);
}

bool TmapServer_UpdateLeAdvertisingData(void)
{
#ifndef INCLUDE_LEGACY_LE_ADVERTISING_MANAGER
    return (tmap_server_registered_handle ? LeAdvertisingManager_UpdateAdvertisingItem(tmap_server_registered_handle) : FALSE);
#else
    return (tmap_server_registered_handle ? LeAdvertisingManager_NotifyDataChange(NULL, tmap_server_registered_handle) : FALSE);
#endif
}
